gdk/x11: Ignore regular crossing events while in implicit grabs
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 9 Jul 2020 14:53:47 +0000 (16:53 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 9 Jul 2020 15:02:07 +0000 (17:02 +0200)
If we create an implicit grab on a surface, leave the surface, and
release the button, we would get 2 XI_Leave events, one with mode
XINotifyNormal when the pointer leaves the surface, and another with
mode XINotifyUngrab when the button is released.

Meanwhile, the upper layers rely on crossing events being paired,
and particularly in no crossing event being sent until the implicit
grab is dismissed (either by releasing it, or via more pervasive
grabs).

Ignoring the set of XINotifyNormal events while an implicit grab
is active adapts the X11 backend to this behavior. If the grab were
released or taken away by another grab, a crossing event with one
of the other XINotify*Grab/XINotify*Ungrab will be generated.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/2879
gdk/x11/gdkdevicemanager-xi2.c

index 0db1865c171c18c5fee3e2328e027a7fb1a61617..de6feaad3d57565acdbdc5b50e6f8a70e3fe9c48 100644 (file)
@@ -1874,6 +1874,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
     case XI_Leave:
       {
         XIEnterEvent *xev = (XIEnterEvent *) ev;
+        GdkModifierType state;
 
         GDK_DISPLAY_NOTE (display, EVENTS,
                   g_message ("%s notify:\twindow %ld\n\tsubwindow:%ld\n"
@@ -1890,6 +1891,18 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         source_device = g_hash_table_lookup (device_manager->id_table,
                                              GUINT_TO_POINTER (xev->sourceid));
 
+        state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+
+        /* Ignore normal crossing events while there is an implicit grab.
+         * We will receive a crossing event with one of the other details if
+         * the implicit grab were finished (eg. releasing the button outside
+         * the window triggers a XINotifyUngrab leave).
+         */
+        if (xev->mode == XINotifyNormal &&
+            (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
+                      GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)))
+          break;
+
         if (ev->evtype == XI_Enter &&
             xev->detail != XINotifyInferior && xev->mode != XINotifyPassiveUngrab &&
             GDK_IS_TOPLEVEL (surface))
@@ -1916,12 +1929,11 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
                                         device,
                                         source_device,
                                         xev->time,
-                                        _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
+                                        state,
                                         (double) xev->event_x / scale,
                                         (double) xev->event_y / scale,
                                         translate_crossing_mode (xev->mode),
                                         translate_notify_type (xev->detail));
-           
       }
       break;
     case XI_FocusIn: